﻿using Nito.AsyncEx;

using PLCS.Client.IService.ConfigManager;
using PLCS.Domain;
using PLCS.Domain.Equipments;
using PLCS.Domain.PLCConfigs;
using PLCS.Domain.Shared.Tasks;
using PLCS.Domain.Tasks;
using PLCS.Domain.Trays;
using PLCS.EquipmentService.ParsersHelpers;
using PLCS.PlcInteraction.Models;
using PLCS.Shared.Common.Constant;
using PLCS.SocialHttpClient.AGV;

using System.Diagnostics;
using System.Threading.Tasks.Dataflow;

namespace PLCS.EquipmentService.BackgroundWorks.EquipmentRun;

[DisallowConcurrentExecution]
public class EquipmentWorker : QuartzBackgroundWorkerBase
{
    private readonly IEquipmentRepository _equipmentRepository;
    private readonly ITaskRepository _taskRepository;
    private readonly IStationRepository _stationRepository;
    private readonly ILogger<EquipmentWorker> _logger;
    private readonly IInstructionRepository _instructionRepository;
    private readonly ExecuteMethod _executeMethod;
    private readonly IRepository<Tray, Guid> _trayRepository;
    private readonly PLCWriter _pLCWriter;
    private readonly PLCSConfigurationService _configService;
    private static AsyncLock _asyncLock = new();
    private readonly AGVSocialService _aGVSocialService;
    private readonly IPLCReadDataRepository _pLCReadDataRepository;
    private readonly TaskParser _taskParser;

    public EquipmentWorker(
        IEquipmentRepository equipmentService,
        ITaskRepository taskService,
        IStationRepository stationRepository,
        ILogger<EquipmentWorker> logger,
        IInstructionRepository instructionRepository,
        ExecuteMethod executeMethod,
        IRepository<Tray, Guid> trayRepository,
        PLCWriter pLCWriter,
        PLCSConfigurationService configService,
        AGVSocialService aGVSocialService,
        IPLCReadDataRepository pLCReadDataRepository,
        TaskParser taskParser)
    {
        _equipmentRepository = equipmentService;
        _taskRepository = taskService;
        _stationRepository = stationRepository;
        _logger = logger;
        _instructionRepository = instructionRepository;
        _executeMethod = executeMethod;
        _trayRepository = trayRepository;
        _pLCWriter = pLCWriter;
        JobDetail = JobBuilder.Create<EquipmentWorker>().WithIdentity(nameof(EquipmentWorker)).Build();
        Trigger = TriggerBuilder.Create().WithIdentity(nameof(EquipmentWorker))
            .WithSimpleSchedule(s => s.WithIntervalInSeconds(1)
            .RepeatForever()
            .WithMisfireHandlingInstructionIgnoreMisfires())
            .Build();

        ScheduleJob = async scheduler =>
        {
            if (!await scheduler.CheckExists(JobDetail.Key))
            {
                await scheduler.ScheduleJob(JobDetail, Trigger);
            }
        };
        _configService = configService;
        _aGVSocialService = aGVSocialService;
        _pLCReadDataRepository = pLCReadDataRepository;
        _taskParser = taskParser;
    }

    public override async Task Execute(IJobExecutionContext context)
    {
        if (await _configService.GetConfiguration("IsTaskRunning") != "1")
        {
            _logger.LogInformation($"当前任务执行已被锁，5秒后重试。");
            await Task.Delay(5000);
            return;
        }
        var stopwatch = Stopwatch.StartNew();

        var unfinshedInstructions = await _instructionRepository.GetUnfinishedInstructionsAsync();

        // 找到每个任务下第一个可执行的指令，如果是手动指令就全部可执行
        var firstExecutableInstructions = unfinshedInstructions
            .GroupBy(x => x.TaskId)
            .Select(group =>
            {
                return group.Key == null ? group.ToList() : new List<Instruction> { group.OrderBy(x => x.InstructionNo).First() };
            })
            .SelectMany(x => x);

        // 找到所有任务下的设备名称，通过这个来开启 TPL 数据流。 Distinct是去重
        var equipmentNames = firstExecutableInstructions.Select(x => x.EquipmentNo).Distinct();

        // 创建一个等待修改的指令集合
        var waitUpdateInstructions = new List<Instruction>();

        var actionBlock = new ActionBlock<string>(async equipmentNum =>
        {
            // 给指令排序，通过任务的优先级来排序，如果不是任务解析出来的，也就是说是自己手动创建的指令，则排到最后，优先级相同则根据创建时间
            var unfinishedInstructions = firstExecutableInstructions.Where(x => x.EquipmentNo == equipmentNum)
            .OrderByDescending(x => x.Task?.Level ?? int.MinValue).ThenBy(x => x.CreationTime);

            if (unfinishedInstructions.Any(x => x.Status == Domain.Shared.Tasks.InstructionStatus.执行中))
                return;

            var equipment = await _equipmentRepository.FindAsync(x => x.EquNum == equipmentNum);
            if (equipment == null) return;

            foreach (var item in unfinishedInstructions)
            {
                var start = !string.IsNullOrWhiteSpace(item.StartPos) ? await _stationRepository.FindAsync(x => x.StaNum == item.StartPos) : null;
                var end = !string.IsNullOrWhiteSpace(item.EndPos) ? await _stationRepository.FindAsync(x => x.StaNum == item.EndPos) : null;

                var lastUnexecutedReason = item.UnexecutedReason;

                // 检查成功后并下发成功即为成功
                var res = await ExceuteCheckAsync(item, unfinshedInstructions, equipment, start, end) && await TaskExecuteAsync(item, equipment, start, end);

                // 下发成功一个之后，就直接跳出。
                if (res)
                {
                    waitUpdateInstructions.Add(item);
                    break;
                }

                // 如果任务执行失败，并且指令的未执行原因不为空，则加入待修改的指令集合当中，等待所有任务遍历完一遍之后，一起修改
                if (!res && !string.IsNullOrEmpty(item.UnexecutedReason) && lastUnexecutedReason != item.UnexecutedReason)
                {
                    waitUpdateInstructions.Add(item);
                }
            }
        }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount / 4 * 3 });

        var doubleActionBlock = new ActionBlock<string>(async equipment =>
        {
            var unfinishedInstructions = firstExecutableInstructions.Where(x => x.EquipmentNo == equipment).OrderBy(X => X.CreationTime);

            // 给指令排序，通过任务的优先级来排序，如果不是任务解析出来的，也就是说是自己手动创建的指令，则排到最后
            unfinishedInstructions = unfinishedInstructions.OrderByDescending(x => x.Task?.Level ?? int.MinValue);

            if (unfinishedInstructions.Any(x => x.Status == Domain.Shared.Tasks.InstructionStatus.执行中))
                return;

            foreach (var item in unfinishedInstructions)
            {
                var lastUnexecutedReason = item.UnexecutedReason;
                var equipments = item.EquipmentNo.Split(ConstantChar.SplitChar);

                var start = !string.IsNullOrWhiteSpace(item.StartPos) ? await _stationRepository.FindAsync(x => x.StaNum == item.StartPos) : null;
                var end = !string.IsNullOrWhiteSpace(item.EndPos) ? await _stationRepository.FindAsync(x => x.StaNum == item.EndPos) : null;

                var equipment1 = await _equipmentRepository.GetByEquipmentNoAsync(equipments[0]);
                var equipment2 = await _equipmentRepository.GetByEquipmentNoAsync(equipments[1]);
                if (equipment1.Status != DeviceStatus.空闲 && equipment2.Status == DeviceStatus.空闲)
                {
                    item.EquipmentNo = equipment2.EquNum;
                    var exeEquipment = await _equipmentRepository.FindAsync(x => x.EquNum == item.EquipmentNo);
                    var res = await ExceuteCheckAsync(item, unfinshedInstructions, exeEquipment, start, end) && await TaskExecuteAsync(item, exeEquipment, start, end);
                    // 下发成功一个之后，就直接跳出。
                    if (res)
                    {
                        break;
                    }
                    // 如果任务执行失败，并且指令的未执行原因不为空，则加入待修改的指令集合当中，等待所有任务遍历完一遍之后，一起修改
                    if (!res && !string.IsNullOrEmpty(item.UnexecutedReason) && lastUnexecutedReason != item.UnexecutedReason)
                    {
                        waitUpdateInstructions.Add(item);
                    }
                }
                else if (equipment2.Status != DeviceStatus.空闲 && equipment1.Status == DeviceStatus.空闲)
                {
                    item.EquipmentNo = equipment1.EquNum;
                    var exeEquipment = await _equipmentRepository.FindAsync(x => x.EquNum == item.EquipmentNo);
                    var res = await ExceuteCheckAsync(item, unfinshedInstructions, exeEquipment, start, end) && await TaskExecuteAsync(item, exeEquipment, start, end);
                    // 下发成功一个之后，就直接跳出。
                    if (res)
                    {
                        break;
                    }
                    // 如果任务执行失败，并且指令的未执行原因不为空，则加入待修改的指令集合当中，等待所有任务遍历完一遍之后，一起修改
                    if (!res && !string.IsNullOrEmpty(item.UnexecutedReason) && lastUnexecutedReason != item.UnexecutedReason)
                    {
                        waitUpdateInstructions.Add(item);
                    }
                }
                else
                {
                    if (equipment1.InTrack == equipment2.InTrack)
                    {
                        var instructions = await _taskParser.GenerateAvoidanceTasksAsync(item, 200);

                        var insCount = instructions.Count;
                        var task = item.Task;
                        var allInstructions = task.Instructions.ToList();
                        instructions.AddRange(allInstructions);
                        instructions.Remove(item);
                        var newInstructions = TaskParser.ReorderTaskNumbers(instructions, item.Task);

                        await _instructionRepository.InsertManyAsync(newInstructions.Take(insCount));
                        await _instructionRepository.DeleteAsync(item);
                        await _instructionRepository.UpdateManyAsync(newInstructions.Skip(insCount));
                    }
                    else
                    {
                        var startStation = await _stationRepository.GetStationByNumAsync(item.StartPos);
                        item.EquipmentNo = Math.Abs(equipment1.CurrentPos - startStation.Position) - Math.Abs(equipment2.CurrentPos - startStation.Position) > 0 ? equipment1.EquNum : equipment2.EquNum;
                        var exeEquipment = await _equipmentRepository.FindAsync(x => x.EquNum == item.EquipmentNo);
                        var res = await ExceuteCheckAsync(item, unfinshedInstructions, exeEquipment, start, end) && await TaskExecuteAsync(item, exeEquipment, start, end);
                        // 下发成功一个之后，就直接跳出。
                        if (res)
                        {
                            break;
                        }
                        // 如果任务执行失败，并且指令的未执行原因不为空，则加入待修改的指令集合当中，等待所有任务遍历完一遍之后，一起修改
                        if (!res && !string.IsNullOrEmpty(item.UnexecutedReason) && lastUnexecutedReason != item.UnexecutedReason)
                        {
                            waitUpdateInstructions.Add(item);
                        }
                    }
                }
            }
        }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount / 4 });
        foreach (var equipment in equipmentNames)
        {
            var equipmentListCount = equipment.Split(ConstantChar.SplitChar).Length;

            if (equipmentListCount == 1)
                await actionBlock.SendAsync(equipment);
            else
                await doubleActionBlock.SendAsync(equipment);
        }
        actionBlock.Complete();
        doubleActionBlock.Complete();
        await Task.WhenAll(actionBlock.Completion, doubleActionBlock.Completion);
        if (waitUpdateInstructions.Any())
            await _instructionRepository.UpdateManyAsync(waitUpdateInstructions);
        // 结束计时并打印执行时间
        stopwatch.Stop();
        var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
        if (elapsedSeconds > 1)
            _logger.LogWarning($"任务执行总时间：{elapsedSeconds}秒");
    }

    /// <summary>
    /// 任务执行方法
    /// </summary>
    /// <returns></returns>
    public async Task<bool> TaskExecuteAsync(Instruction instruction, Equipment equipment, Station? start, Station? end)
    {
        // 如果是任务下的第一个指令开始执行，那么就要执行一下任务前方法
        var stations = await _stationRepository.GetStationListAsync();
        if (instruction.TaskId != null)
        {
            // 同一组任务 之前的任务没执行完成，则直接跳出
            // 如果是任务下的第一个指令开始执行，那么就要执行一下任务前方法
            int index = GetIndexFromInstructionNo(instruction.InstructionNo);
            var task = instruction.Task;
            if (task == null) return false;
            if (index == 1)
            {
                if (!string.IsNullOrEmpty(task.BeforeExecutionMethod))
                    _executeMethod.ExecuteTriggerMethod("BeforeExecutionMethod", task.BeforeExecutionMethod, task.BeforeExecutionParam);
            }
        }

        // 获取起始目标位，这边下发要下发PLC的工位编号。
        string plcStart = string.Empty, plcEnd = string.Empty;
        string agvStart = string.Empty, agvEnd = string.Empty;
        if (start != null)
        {
            plcStart = start.StaName_Lower;
            agvStart = start.StaName_Higher;
        }
        if (end != null)
        {
            plcEnd = end.StaName_Lower;
            agvEnd = end.StaName_Higher;
        }

        bool result = false;

        if (equipment.EquType == EquipmentType.AGV)
        {
            var respone = await _aGVSocialService.ReleaseTaskAsync(instruction.InstructionNo.ToString(), equipment.EquNum, agvStart, agvEnd);
            result = respone.Header.Code == "S";
        }
        else
        {
            var plcreadData = await _pLCReadDataRepository.FindPLCReadDataByNoAsync($"{instruction.EquipmentNo}_Current_TaskId");
            int readDb = plcreadData?.PLCConfig?.DBNumber ?? 0;
            int readStart = plcreadData?.StartBit ?? 0;
            var workingStation = await _stationRepository.GetStationByNumAsync(instruction.ContainStationNo);

            PlcWorkParam plcWorkParam = new PlcWorkParam(instruction.InstructionNo, instruction.InstructionType, instruction.TrayType, 1, plcStart, plcEnd, workingStation.StaName_Lower, instruction.MovePos, 1);
            result = _pLCWriter.ExcuteTask(equipment.Plc_Index, equipment.PLCAddress, equipment.Rack, equipment.Slot, equipment.DbNumber, readDb, readStart, plcWorkParam);
        }

        if (!result)
        {
            _logger.LogError($"下发任务{instruction.InstructionNo}失败！设备编号：{equipment.EquNum}");
            DisposeCheckResult(false, instruction, "下发任务失败");
            return false;
        }

        instruction.ChangeStatus(Domain.Shared.Tasks.InstructionStatus.执行中);
        instruction.InitalPos = equipment.CurrentPos;
        _logger.LogInformation($"下发PLC任务{instruction.InstructionNo}成功！");

        if (instruction.TaskId != null && instruction.Task != null)
        {
            instruction.Task.ChangeStatus(Domain.Shared.Tasks.TaskStatus.执行中);
        }

        DisposeCheckResult(true, instruction, instruction.UnexecutedReason);

        // 执行中之后，锁住起始和目标中的工位
        int currentPos = equipment.CurrentPos;
        if (end == null && start != null && start.Position != 0)
        {
            await LockIntermediatePositions(start.Position, currentPos);
        }
        else if (start == null && end != null && end.Position != 0)
        {
            await LockIntermediatePositions(end.Position, currentPos);
        }
        else if (start != null && end != null && end.Position != 0 && start.Position != 0)
        {
            int minTaskPosition = Math.Min(start.Position, end.Position);
            int maxTaskPosition = Math.Max(start.Position, end.Position);
            await LockIntermediatePositions(minTaskPosition, maxTaskPosition);
        }
        else if (instruction.InstructionType == InstructionType.单坐标行走)
        {
            int minTaskPosition = Math.Min(instruction.MovePos, currentPos);
            int maxTaskPosition = Math.Max(instruction.MovePos, currentPos);
            await LockIntermediatePositions(minTaskPosition, maxTaskPosition);
        }
        return true;
    }

    /// <summary>
    /// 任务执行前检查
    /// </summary>
    /// <returns></returns>
    public async Task<bool> ExceuteCheckAsync(Instruction instruction, IEnumerable<Instruction> allUnfinishedInstructions, Equipment equipment, Station? start, Station? end)
    {
        bool res;

        // TODO:确认执行工位

        if (string.IsNullOrEmpty(instruction.ContainStationNo))
        {
            List<string> startMultipleTrayTypes = start?.MultipleTrayType?.Split(ConstantChar.SplitChar).ToList() ?? new List<string>();
            List<string> endMultipleTrayTypes = end?.MultipleTrayType?.Split(ConstantChar.SplitChar).ToList() ?? new List<string>();

            List<string> containStationMultipleTrayTypes = new();
            var containStations = new List<Station>();

            var containStationNos = equipment.ContainStationNos.Split(ConstantChar.SplitChar);
            if (containStationNos.Count() == 1)
                instruction.ContainStationNo = containStationNos.First();
            else
            {
                foreach (var item in containStationNos)
                {
                    var containStation = await _stationRepository.GetStationByNumAsync(item);
                    containStations.Add(containStation);
                    containStationMultipleTrayTypes.AddRange(containStation.MultipleTrayType.Split(ConstantChar.SplitChar).ToList());
                }

                var commonMultipleTrayTypes = Utility.FindCommonElements(startMultipleTrayTypes, endMultipleTrayTypes, containStationMultipleTrayTypes);

                if (commonMultipleTrayTypes != null)
                {
                    var stationsWithCommonTrayTypes = Utility.FindStationsWithCommonTrayTypes(commonMultipleTrayTypes, containStations);

                    var choseWorkStation = stationsWithCommonTrayTypes
                        .FirstOrDefault(x => x.IsUse == YesNo.是 && x.IsLocked == YesNo.否 && !allUnfinishedInstructions.Select(x => x.ContainStationNo).Contains(x.StaNum))
                       ?? stationsWithCommonTrayTypes.FirstOrDefault();

                    if (choseWorkStation != null)
                    {
                        instruction.ContainStationNo = choseWorkStation.StaNum;
                    }
                }
            }
        }

        // TODO：判断RGV行驶路径上有没有阻挡的RGV，有的话需要移开
        res = await CheckObstaclesInRGVPathAsync(instruction, equipment, start, end);
        if (!res) return false;

        res = await UniversalCheck(instruction, allUnfinishedInstructions, equipment, start, end);
        if (!res) return false;

        // TODO：其他特殊检查

        return res;
    }

    public async Task<bool> CheckObstaclesInRGVPathAsync(Instruction instruction, Equipment equipment, Station? start, Station? end)
    {
        if (equipment.EquType != EquipmentType.RGV || string.IsNullOrEmpty(equipment.InTrack))
            return true;

        var equipments = await _equipmentRepository.GetByTrackAsync(equipment.InTrack);
        equipments = equipments.Where(x => x.EquNum != equipment.EquNum);
        // 没有的话说明这个轨道上只有一个RGV。
        if (!equipments.Any())
            return true;

        if (instruction.Task == null)
            return false;

        // 获取起始目标位，这边下发要下发PLC的工位编号。
        int maxTaskPosition = int.MaxValue;
        int minTaskPosition = int.MinValue;
        if (end == null && start != null && start.Position != 0)
        {
            maxTaskPosition = Math.Max(start.Position, equipment.CurrentPos);
            minTaskPosition = Math.Min(start.Position, equipment.CurrentPos);
        }
        else if (start == null && end != null && end.Position != 0)
        {
            maxTaskPosition = Math.Max(end.Position, equipment.CurrentPos);
            minTaskPosition = Math.Min(end.Position, equipment.CurrentPos);
        }
        else if (start != null && end != null && end.Position != 0 && start.Position != 0)
        {
            maxTaskPosition = Math.Max(start.Position, end.Position); // 起始位和目标位的最大值
            minTaskPosition = Math.Min(start.Position, end.Position); // 起始位和目标位的最小值
        }
        else if (instruction.InstructionType == InstructionType.单坐标行走)
        {
            maxTaskPosition = Math.Max(instruction.MovePos, equipment.CurrentPos);
            minTaskPosition = Math.Min(instruction.MovePos, equipment.CurrentPos);
        }
        else
            return true;

        if (equipment.CurrentPos < minTaskPosition)
            minTaskPosition = equipment.CurrentPos;
        if (equipment.CurrentPos > maxTaskPosition)
            maxTaskPosition = equipment.CurrentPos;

        foreach (var item in equipments)
        {
            var tasks = await _instructionRepository.GetListAsync(x => x.EquipmentNo == item.EquNum && x.Status == InstructionStatus.执行中);
            if (tasks.Any())
            {
                return false;
            }
            if (item.CurrentPos > minTaskPosition - LocalConfigManager.SafeDistance && item.CurrentPos < maxTaskPosition + LocalConfigManager.SafeDistance)
            {
                // TODO:下发一个任务让他移走

                var moveStationPos = equipment.CurrentPos < item.CurrentPos ? minTaskPosition - LocalConfigManager.SafeDistance : maxTaskPosition + LocalConfigManager.SafeDistance;
                var moveInstruction = new Instruction(1, instruction.TaskId, item.EquNum, InstructionType.单坐标行走);
                moveInstruction.SetMovePos(moveStationPos);
                var instructions = new List<Instruction>();
                instructions.Add(moveInstruction);
                instructions.Add(new Instruction(2, instruction.TaskId, equipment.EquNum, InstructionType.取放货, instruction.StartPos, instruction.EndPos));

                var insCount = instructions.Count;
                var task = instruction.Task;
                var allInstructions = task.Instructions?.ToList();
                instructions.AddRange(allInstructions);
                instructions.Remove(instruction);
                var newInstructions = TaskParser.ReorderTaskNumbers(instructions, instruction.Task);

                await _instructionRepository.InsertManyAsync(newInstructions.Take(insCount));
                await _instructionRepository.DeleteAsync(instruction);
                await _instructionRepository.UpdateManyAsync(newInstructions.Skip(insCount));
            }
        }
        return false;
    }

    /// <summary>
    /// 通用的任务执行前检查
    /// </summary>
    /// <returns></returns>
    public async Task<bool> UniversalCheck(Instruction instruction, IEnumerable<Instruction> allUnfinishedInstructions, Equipment equipment, Station? start, Station? end)
    {
        bool res = true;

        var task = instruction.Task;

        var containStation = await _stationRepository.GetStationByNumAsync(instruction.ContainStationNo);
        res = containStation != null;
        DisposeCheckResult(res, instruction, $"包含工位不存在，请连续管理员");
        if (!res) return res;
        // 将指令号转换为字符串
        string s = instruction.InstructionNo.ToString();

        // 检查字符串长度是否为 9 位数
        if (s.Length == 9)
        {
            int instructionNo = instruction.InstructionNo - 1;
            var IslastInstruction = !allUnfinishedInstructions.Any(x => x.InstructionNo == instructionNo);
            res = IslastInstruction;
            DisposeCheckResult(res, instruction, $"任务下的上一条指令还未完成");
            if (!res) return res;
        }

        res = equipment.IsUse == YesNo.是;
        DisposeCheckResult(res, instruction, $"设备{equipment.EquName}暂停使用");
        if (!res) return res;

        res = equipment.IsLocked == YesNo.否;
        DisposeCheckResult(res, instruction, $"设备{equipment.EquName}被锁定");
        if (!res) return res;

        res = equipment.OnlineStatus == Domain.Shared.Equipments.OnlineMode.联机;
        DisposeCheckResult(res, instruction, $"设备{equipment.EquName}不处于联机状态");
        if (!res) return res;

        res = equipment.Status == DeviceStatus.空闲;
        DisposeCheckResult(res, instruction, $"设备{equipment.EquName}不处于空闲状态");
        if (!res) return res;

        switch (instruction.InstructionType)
        {
            case InstructionType.工位行走:
                return true;

            case InstructionType.单坐标行走:
                return true;

            case InstructionType.单取货:
                res = containStation.HaveStatus == YesNo.否;
                DisposeCheckResult(res, instruction, $"设备{equipment.EquName}的包含工位{containStation.StaNum}满位");
                if (!res) return res;

                res = CheckStartPos(instruction, start);
                if (!res) return res;
                break;

            case InstructionType.单放货:
                res = containStation.HaveStatus == YesNo.是;
                DisposeCheckResult(res, instruction, $"设备{equipment.EquName}的包含工位{containStation.StaNum}空位");
                if (!res) return res;
                res = CheckEndPos(instruction, end);
                if (!res) return res;
                break;

            case InstructionType.取放货:
                res = containStation.HaveStatus == YesNo.否;
                DisposeCheckResult(res, instruction, $"设备{equipment.EquName}的包含工位{containStation.StaNum}空位");
                if (!res) return res;

                res = CheckStartPos(instruction, start);
                if (!res) return res;

                res = CheckEndPos(instruction, end);
                if (!res) return res;
                break;

            default:
                throw new NotSupportedException("任务类型不支持");
        }

        return res;
    }

    /// <summary>
    /// 检查起始工位
    /// </summary>
    /// <param name="instruction"></param>
    /// <returns></returns>
    private bool CheckStartPos(Instruction instruction, Station startPos)
    {
        var res = true;

        res = startPos != null;
        DisposeCheckResult(res, instruction, $"起始工位不存在，请检查输入无误。");
        if (!res) return res;

        if (!string.IsNullOrWhiteSpace(startPos?.CanTake_EquNum))
        {
            res = startPos.CanTake_EquNum.Contains(instruction.EquipmentNo);
            DisposeCheckResult(res, instruction, $"该工位不可被{instruction.EquipmentNo}取，请检查输入无误。");
            if (!res) return res;
        }

        //res = startPos?.StaStatus == DeviceStatus.空闲;
        //DisposeCheckResult(res, instruction, $"工位{startPos.StaNum}不处于空闲状态");
        //if (!res) return res;

        if (startPos != null && (startPos.StationType == Domain.Shared.Stations.StationType.栈工位 || startPos.StationType == Domain.Shared.Stations.StationType.队列工位))
        {
            res = startPos.TrayCount > 0;
            DisposeCheckResult(res, instruction, $"工位{startPos.StaNum}空位");
            if (!res) return res;
        }
        else
        {
            res = startPos?.HaveStatus == YesNo.是;
            DisposeCheckResult(res, instruction, $"工位{startPos.StaNum}空位");
            if (!res) return res;
        }

        res = startPos?.CanOutStatus[instruction.EquipmentNo] == YesNo.是;
        DisposeCheckResult(res, instruction, $"工位{startPos.StaNum}不可出");
        if (!res) return res;

        res = startPos?.IsUse == YesNo.是;
        DisposeCheckResult(res, instruction, $"工位{startPos.StaNum}不可用");
        if (!res) return res;

        return res;
    }

    /// <summary>
    /// 检查目标工位
    /// </summary>
    /// <param name="instruction"></param>
    /// <returns></returns>
    private bool CheckEndPos(Instruction instruction, Station endPos)
    {
        var res = true;

        res = endPos != null;
        DisposeCheckResult(res, instruction, $"目标工位不存在，请检查输入无误。");
        if (!res) return res;

        if (!string.IsNullOrWhiteSpace(endPos?.CanSend_EquNum))
        {
            res = endPos.CanSend_EquNum.Contains(instruction.EquipmentNo);
            DisposeCheckResult(res, instruction, $"该工位不可被{instruction.EquipmentNo}送，请检查输入无误。");
            if (!res) return res;
        }

        //res = endPos?.StaStatus == DeviceStatus.空闲;
        //DisposeCheckResult(res, instruction, $"工位{endPos.StaNum}不处于空闲状态");
        //if (!res) return res;

        if (endPos != null && (endPos.StationType == Domain.Shared.Stations.StationType.栈工位 || endPos.StationType == Domain.Shared.Stations.StationType.队列工位))
        {
            res = endPos.TrayCount < endPos.Capacity;
            DisposeCheckResult(res, instruction, $"工位{endPos.StaNum}满位");
            if (!res) return res;
        }
        else
        {
            res = endPos?.HaveStatus == YesNo.否;
            DisposeCheckResult(res, instruction, $"工位{endPos.StaNum}满位");
            if (!res) return res;
        }

        res = endPos?.CanInSideStatus[instruction.EquipmentNo] == YesNo.是;
        DisposeCheckResult(res, instruction, $"工位{endPos.StaNum}不可进");
        if (!res) return res;

        res = endPos?.IsUse == YesNo.是;
        DisposeCheckResult(res, instruction, $"工位{endPos.StaNum}不可用");
        if (!res) return res;

        return res;
    }

    /// <summary>
    /// 处理检查结果
    /// </summary>
    /// <param name="taskId"></param>
    /// <param name="res"></param>
    /// <param name="exceptionMsg"></param>
    /// <returns></returns>
    public void DisposeCheckResult(bool res, Instruction instruction, string exceptionMsg)
    {
        if (res)
        {
            if (!string.IsNullOrEmpty(instruction?.UnexecutedReason))
            {
                instruction.UnexecutedReason = string.Empty;
            }
        }
        else
        {
            if (string.IsNullOrEmpty(instruction?.UnexecutedReason) || instruction.UnexecutedReason != exceptionMsg)
            {
                instruction.UnexecutedReason = exceptionMsg ?? string.Empty;
            }
        }
    }

    public int GetIndexFromInstructionNo(int instructionNo)
    {
        // 将指令号转换为字符串
        string s = instructionNo.ToString();

        // 检查字符串长度是否为 9 位数
        if (s.Length != 9)
        {
            return -1; // -1说明不是9位数，也就是说这不是任务拆解出来的指令
        }

        // 获取 taskId 和 index 的字符串表示
        string taskIdStr = s.Substring(0, 4);
        string indexStr = s.Substring(4);

        // 转换 taskId 和 index 字符串为 int 类型，并计算 index 的值
        int taskId = int.Parse(taskIdStr);
        int index = int.Parse(indexStr);

        return index;
    }

    private async Task LockIntermediatePositions(int minPosition, int maxPosition)
    {
        int safeDistance = LocalConfigManager.SafeDistance;
        int minTaskPosition = minPosition - safeDistance;
        int maxTaskPosition = maxPosition + safeDistance;

        // 找到最小坐标和最大坐标之间的所有工位，并锁住
        var needLockStations = await _stationRepository.GetIntermediatePositions(minTaskPosition, maxTaskPosition);
        foreach (Station item in needLockStations)
        {
            item.IsLocked = YesNo.是;
        }

        await _stationRepository.UpdateManyAsync(needLockStations);
    }
}